#include "opportunity.hpp"
#include "types.h"
#include <cstdio>
#include <cstdlib>

/*
           ,-----.
         ,'_/_|_\_`.
        /<<::8[O]::>\
       _|-----------|_
   :::|  | ====-=- |  |:::
   :::|  | -=-==== |  |:::
   :::\  | ::::|()||  /:::
   ::::| | ....|()|| |::::  -Don
       | |_________| |
       | |\_______/| |
      /   \ /   \ /   \   R2 Astromech Droid (2)
      `---' `---' `---'       - Front View -
*/

namespace Trade {

void
Opportunity::print() const noexcept
{
  printf("OppU Trent %d %d %% Force %d  %d %% Virtusl %d %d %%\n",
         trend_up,
         trend_dn,
         force_up,
         force_dn,
         vision_up,
         vision_dn);
}

dir_t
Opportunity::get_virutal_dir() const noexcept
{
  return (vision_up > vision_dn ? 1 : (vision_dn > vision_up ? -1 : 0));
}

dir_t
Opportunity::get_oppor_dir() const noexcept
{
  return (oppor_up > oppor_dn ? 1 : (oppor_dn > oppor_up ? -1 : 0));
}

percent_t
Opportunity::get_cur_percent() const noexcept
{
  return (oppor_up > oppor_dn ? oppor_up
                              : (oppor_dn > oppor_up ? oppor_dn : 0));
}

dir_t
Opportunity::get_stable_dir() const noexcept
{
  dir_t d = 0;
  int up = trend_up + force_up;
  int dn = trend_dn + force_dn;

  if (up > dn) {
    d = 1;
  } else if (up < dn) {
    d = -1;
  }
  return d;
}

percent_t
Opportunity::get_stable_percent() const noexcept
{
  int up = trend_up + force_up;
  int dn = trend_dn + force_dn;
  if (up > dn) {
    up = int(float(up) / float(dn + up) * 100);
    return up;
  } else if (up < dn) {
    dn = -int(float(dn) / float(dn + up) * 100);
    return dn;
  } else {
    return (0);
  }
}

dir_t
Opportunity::get_trend_dir() const noexcept
{
  return (trend_up > trend_dn ? 1 : (trend_dn > trend_up ? -1 : 0));
}

dir_t
Opportunity::get_force_dir() const noexcept
{
  return (force_up > force_dn ? 1 : (force_dn > force_up ? -1 : 0));
}

static OPPUT_DIFF_TYPE
get_difference_(const percent_t up, const percent_t dn) noexcept
{
  OPPUT_DIFF_TYPE odt = OPPUT_DIFF_TYPE::UNKNOW;
  if (dn == up)
    odt = OPPUT_DIFF_TYPE::SAME;
  else if (std::abs(dn - up) < 20)
    odt = OPPUT_DIFF_TYPE::SMALL;
  else
    odt = OPPUT_DIFF_TYPE::LARGE;

  return odt;
}

OPPUT_DIFF_TYPE
Opportunity::get_opportunity_difference() const noexcept
{
  return get_difference_(oppor_up, oppor_dn);
}

OPPUT_DIFF_TYPE
Opportunity::get_virutal_difference() const noexcept
{
  return get_difference_(vision_up, vision_dn);
}

OPPUT_DIFF_TYPE
Opportunity::get_trend_difference() const noexcept
{
  return get_difference_(trend_up, trend_dn);
}

OPPUT_DIFF_TYPE
Opportunity::get_force_difference() const noexcept
{
  return get_difference_(force_up, force_dn);
}

bool
Opportunity::good() const noexcept
{
  return (trend_dn && trend_up && force_dn && force_up && vision_dn &&
          vision_up);
}

dir_t
OpportunitySeries::add_new_opportunity(const dir_t d,
                                       const percent_t pct,
                                       const time_t tm,
                                       const price_t hpx) noexcept
{
  auto op = ov.back();
  if (!op || op->dir_oppor != d) {
    Oppor o;
    o.dir_oppor = d;
    o.pct_max = o.pct_min = o.pct_oppor = pct;
    o.hpx_max = o.hpx_min = hpx;
    o.tm_min = o.tm_max = tm;
    ov.new_data(o);

    if (op) {
      const dir_t d_cp =
        (pct > op->pct_oppor) ? d : (pct < op->pct_oppor ? op->dir_oppor : 0);
      return d_cp;
    } else {
      return d;
    }
  } else {
    if (op->pct_oppor < pct) {
      op->pct_max = pct;
    }
    if (op->pct_oppor > pct) {
      op->pct_min = pct;
    }
    op->pct_oppor = pct;
    op->tm_max = tm;
    if (op->hpx_max < hpx) {
      op->hpx_max = hpx;
    }
    if (op->hpx_min > hpx) {
      op->hpx_min = hpx;
    }
    return d;
  }
}

dir_t
OpportunitySeries::large_oppor(const time_t tm,
                               const price_t hpx) const noexcept
{
  return (0);
}

} // namespace Trade